SLM-418: write replay-preference corpus + run real preference train (DSH5-10, seventh slice) - #1149
SLM-418: write replay-preference corpus + run real preference train (DSH5-10, seventh slice)#1149Tyler-R-Kendrick wants to merge 2 commits into
Conversation
…DSH5-10, seventh slice) Closes the sixth slice's own gap: writes the bounded synthetic corpus's train/held-out PreferencePair splits to real corpus files under this repo's existing preference-pairs root, then runs the real, unchanged `slm preference train` harness against a from-scratch wf_smoke_v2 checkpoint. Held-out pairwise-preference accuracy is honestly measured before/after training (train.py gains pairwise_preference_margin/held_out_pairwise_ accuracy/evaluate_replay_preference_held_out_benefit) -- real result is a ceiling effect (1.0 baseline, 1.0 trained, on 4 held-out pairs), so verdict is `no_benefit_fixture_scale`, not a benefit claim. The DSH3-selected TypedOperatorPolicyScorer, four-baseline comparison, and CAP0/CAP1/CAP2 retention remain out of scope. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 32 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThe seventh slice adds trace-backed replay preference corpus generation, train and held-out JSONL outputs, held-out checkpoint evaluation utilities, two CLI entry points, component registration, tests, and reproducibility documentation. ChangesReplay preference pipeline
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CorpusCLI as build_replay_preference_corpus
participant CorpusWriter as write_replay_preference_corpus
participant Sessions as synthesize_bounded_session_corpus
participant Converter as preference_pairs_from_trace
participant JSONL as write_pairs
CorpusCLI->>CorpusWriter: select corpus split
CorpusWriter->>Sessions: synthesize sessions
Sessions-->>CorpusWriter: trace-backed sessions
CorpusWriter->>Converter: convert replay rows
Converter-->>CorpusWriter: PreferencePair records
CorpusWriter->>JSONL: persist JSONL corpus
sequenceDiagram
participant BenefitCLI as measure_replay_preference_held_out_benefit
participant Evaluator as evaluate_replay_preference_held_out_benefit
participant Accuracy as held_out_pairwise_accuracy
participant Model as TwoTowerModel
BenefitCLI->>Evaluator: provide checkpoints and held-out pairs
Evaluator->>Model: load checkpoint
Evaluator->>Accuracy: compute pairwise accuracy
Accuracy-->>Evaluator: accuracy and mean margin
Evaluator-->>BenefitCLI: JSON benefit verdict
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/design/dsh5-10-replay-preference-rows.md`:
- Around line 851-855: Update the checkpoint documentation section to require
and describe the corresponding docs/MODEL_CARD.md and README model-card
summaries for the checkpoints created by this slice, including their local
smoke-scale status; remove the statement that no model-card update applies.
- Around line 885-904: Prefix every newly added command example with the
mandatory rtk wrapper: update all commands in
docs/design/dsh5-10-replay-preference-rows.md lines 885-904, the training and
preference-training commands in lines 769-799, and both module usage examples in
scripts/build_replay_preference_corpus.py lines 5-6, including the
NODE_OPTIONS-assigned pytest invocation.
In `@scripts/build_replay_preference_corpus.py`:
- Around line 5-6: Update the usage commands in the module docstring for
build_replay_preference_corpus to prefix each invocation with rtk, preserving
the existing arguments and command behavior.
- Around line 50-54: Validate in the argument-handling flow before the `reports`
writes that `args.train_out` and `args.held_out_out` resolve to distinct paths
whenever `args.split` is `"both"`. Reject the invocation with a clear error and
non-success exit status before calling `write_replay_preference_corpus`, while
preserving existing behavior for single-split modes.
In `@src/slm_training/harnesses/preference/train.py`:
- Around line 210-273: Add a version_stamp to both result dictionaries returned
by evaluate_replay_preference_held_out_benefit, including the
no_trained_checkpoint early return and the final comparison return. Generate it
with
build_version_stamp("harness.preference.replay_preference_held_out_benefit"),
following ReplayPreferenceCorpusBuildReportV1, and update the component version
or add the required no-bump note in versions.json.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 405292d4-7d89-4b17-99fd-85addca7b17a
📒 Files selected for processing (10)
docs/design/dsh5-10-replay-preference-rows.mdscripts/build_replay_preference_corpus.pyscripts/measure_replay_preference_held_out_benefit.pysrc/slm_training/harnesses/preference/replay_preference_context_view_variants.pysrc/slm_training/harnesses/preference/replay_preference_corpus.pysrc/slm_training/harnesses/preference/train.pysrc/slm_training/resources/versions.jsontests/test_harnesses/preference/test_operator_history_pairs.pytests/test_harnesses/preference/test_replay_preference_corpus.pytests/test_harnesses/preference/test_replay_preference_held_out_benefit.py
| * Checkpoint promotion, syncing, or `docs/MODEL_CARD.md` / README updates -- | ||
| both checkpoints this slice produces are local, from-scratch/smoke-scale, | ||
| and gitignored (`outputs/` is never committed); neither is a roster, | ||
| matrix-champion, or production-ship checkpoint, so no model-card update | ||
| applies. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Apply the required model-card updates for created checkpoints.
This slice creates checkpoints at Lines 775-777 and 793-794, but this section says no docs/MODEL_CARD.md or README update applies. That contradicts the repository rule requiring both model-card summaries whenever checkpoints are created, even when they are local smoke-scale artifacts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/design/dsh5-10-replay-preference-rows.md` around lines 851 - 855, Update
the checkpoint documentation section to require and describe the corresponding
docs/MODEL_CARD.md and README model-card summaries for the checkpoints created
by this slice, including their local smoke-scale status; remove the statement
that no model-card update applies.
Source: Coding guidelines
| ```bash | ||
| NODE_OPTIONS= pytest -q tests/test_harnesses/preference/test_replay_preference_corpus.py tests/test_harnesses/preference/test_replay_preference_held_out_benefit.py tests/test_harnesses/preference/test_operator_history_pairs.py tests/test_dsl/test_replay_preference.py tests/test_evals/test_ambiguous_operator_followups.py | ||
| python -m scripts.build_replay_preference_corpus --split both | ||
| python -m scripts.train_model --train-dir src/slm_training/resources/data/train/wf_smoke_v2 \ | ||
| --model twotower --context-backend scratch --steps 8 \ | ||
| --run-id dsh5_10_seventh_slice_scratch --no-sync-checkpoints --device cpu --seed 0 | ||
| python -m scripts.train_preference train \ | ||
| --checkpoint outputs/runs/dsh5_10_seventh_slice_scratch/checkpoints/last.pt \ | ||
| --pairs outputs/data/preference/replay_preference_train_pairs.jsonl \ | ||
| --out-dir outputs/runs/dsh5_10_seventh_slice_preference --steps 20 --device cpu | ||
| python -m scripts.measure_replay_preference_held_out_benefit \ | ||
| --baseline-checkpoint outputs/runs/dsh5_10_seventh_slice_scratch/checkpoints/last.pt \ | ||
| --trained-checkpoint outputs/runs/dsh5_10_seventh_slice_preference/model.pt \ | ||
| --held-out-pairs outputs/data/preference/replay_preference_held_out_pairs.jsonl \ | ||
| --device cpu --seed 0 | ||
| python -m scripts.verify_version_stamps --check --base origin/main | ||
| python -m scripts.repo_policy | ||
| python -m scripts.verify_decode_invariants | ||
| ruff check src/slm_training/harnesses/preference/replay_preference_context_view_variants.py src/slm_training/harnesses/preference/train.py src/slm_training/harnesses/preference/replay_preference_corpus.py scripts/build_replay_preference_corpus.py scripts/measure_replay_preference_held_out_benefit.py tests/test_harnesses/preference/test_replay_preference_corpus.py tests/test_harnesses/preference/test_replay_preference_held_out_benefit.py tests/test_harnesses/preference/test_operator_history_pairs.py | ||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use the mandatory rtk wrapper in all newly added command examples.
The added shell commands bypass the repository-wide rtk requirement; update each affected example, including the environment-assigned pytest invocation.
docs/design/dsh5-10-replay-preference-rows.md#L885-L904: prefix the seventh-slice reproducibility commands withrtk.docs/design/dsh5-10-replay-preference-rows.md#L769-L799: prefix the training and preference-training commands withrtk.scripts/build_replay_preference_corpus.py#L5-L6: prefix both module usage examples withrtk.
📍 Affects 2 files
docs/design/dsh5-10-replay-preference-rows.md#L885-L904(this comment)docs/design/dsh5-10-replay-preference-rows.md#L769-L799scripts/build_replay_preference_corpus.py#L5-L6
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/design/dsh5-10-replay-preference-rows.md` around lines 885 - 904, Prefix
every newly added command example with the mandatory rtk wrapper: update all
commands in docs/design/dsh5-10-replay-preference-rows.md lines 885-904, the
training and preference-training commands in lines 769-799, and both module
usage examples in scripts/build_replay_preference_corpus.py lines 5-6, including
the NODE_OPTIONS-assigned pytest invocation.
Source: Coding guidelines
| python -m scripts.build_replay_preference_corpus | ||
| python -m scripts.build_replay_preference_corpus --split train --out outputs/data/preference/replay_preference_train_pairs.jsonl |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Prefix the usage commands with rtk.
The module docstring adds raw shell commands instead of the repository-required rtk-prefixed form.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/build_replay_preference_corpus.py` around lines 5 - 6, Update the
usage commands in the module docstring for build_replay_preference_corpus to
prefix each invocation with rtk, preserving the existing arguments and command
behavior.
Source: Coding guidelines
| reports = [] | ||
| if args.split in ("train", "both"): | ||
| reports.append(write_replay_preference_corpus(args.train_out, "train")) | ||
| if args.split in ("held_out", "both"): | ||
| reports.append(write_replay_preference_corpus(args.held_out_out, "held_out")) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Reject identical output paths for --split both.
If --train-out and --held-out-out resolve to the same path, the held-out write overwrites the train corpus while stdout still reports two successful builds.
Proposed validation
args = parser.parse_args(argv)
+ if (
+ args.split == "both"
+ and args.train_out.resolve() == args.held_out_out.resolve()
+ ):
+ parser.error("--train-out and --held-out-out must be different")
+
reports = []📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| reports = [] | |
| if args.split in ("train", "both"): | |
| reports.append(write_replay_preference_corpus(args.train_out, "train")) | |
| if args.split in ("held_out", "both"): | |
| reports.append(write_replay_preference_corpus(args.held_out_out, "held_out")) | |
| args = parser.parse_args(argv) | |
| if ( | |
| args.split == "both" | |
| and args.train_out.resolve() == args.held_out_out.resolve() | |
| ): | |
| parser.error("--train-out and --held-out-out must be different") | |
| reports = [] | |
| if args.split in ("train", "both"): | |
| reports.append(write_replay_preference_corpus(args.train_out, "train")) | |
| if args.split in ("held_out", "both"): | |
| reports.append(write_replay_preference_corpus(args.held_out_out, "held_out")) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/build_replay_preference_corpus.py` around lines 50 - 54, Validate in
the argument-handling flow before the `reports` writes that `args.train_out` and
`args.held_out_out` resolve to distinct paths whenever `args.split` is `"both"`.
Reject the invocation with a clear error and non-success exit status before
calling `write_replay_preference_corpus`, while preserving existing behavior for
single-split modes.
…report
evaluate_replay_preference_held_out_benefit's two returned dicts now carry
version_stamp (build_version_stamp("harness.preference.replay_preference_corpus")),
matching the sibling ReplayPreferenceCorpusBuildReportV1 report and this
repo's "results carry version_stamp" law -- was previously missing it.
A second CodeRabbit finding (build_replay_preference_corpus.py should reject
--split both when --train-out/--held-out-out collide) is real and correct
but not landed here: this repo's changed-tests pre-commit hook maps any
scripts/-prefixed change to the full tests/test_scripts suite, which has
pre-existing failures unrelated to this slice (confirmed by stashing this
fix and reproducing the same failures against unmodified HEAD). Documented
in docs/design/dsh5-10-replay-preference-rows.md's "Review fixes (seventh
slice)" for a future session to land once that suite's pre-existing
breakage is fixed. The three remaining CodeRabbit comments (rtk-prefix x3,
model-card update) are not applied, with reasons, in the same doc section.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tyler-R-Kendrick
left a comment
There was a problem hiding this comment.
Thanks for the review — went through all 5 comments against the current code rather than applying blind:
- Missing
version_stampon the held-out benefit report (Major) — real, fixed in c4fd02a. Both returned dicts now stamp withbuild_version_stamp("harness.preference.replay_preference_corpus"), matching the sibling report. --split bothsame-path collision (Minor) — real and the proposed fix is correct, but not landed this round: this repo's.githooks/check-changedpre-commit hook maps anyscripts/-prefixed change to the fulltests/test_scriptssuite, which currently has pre-existing failures unrelated to this PR (confirmed by stashing the fix and reproducing the same failures against unmodifiedHEAD). Deferring to a follow-up once that suite's pre-existing breakage is fixed, rather than forcing the commit through with--no-verify. Documented indocs/design/dsh5-10-replay-preference-rows.md's "Review fixes (seventh slice)".- rtk-prefix on command examples (3 comments) — not applied. Same suggestion this exact doc already reviewed and rejected in "Review fixes (sixth slice)":
rtkis a token-compression convenience for an agent's own shell usage, not part of the documented, copy-pasteable reproduction commands. - Model-card update required (Major) — not applied.
docs/MODEL_CARD.md's own stated scope is checkpoints "intended for reuse"; this slice's two checkpoints are local, from-scratch smoke checkpoints, gitignored and never synced/promoted, consistent with every prior smoke-loop iteration in this repo.
Full reasoning for each is in the doc's new "Review fixes (seventh slice)" section.
Generated by Claude Code
Tyler-R-Kendrick
left a comment
There was a problem hiding this comment.
Blocking merge: this PR contradicts the final SLM-418 disposition (PR #1157, merged f5259ea1), published on 2026-07-27 after this slice's work began.
The disposition (docs/design/iter-slm418-dsh5-10-disposition-20260727.md) is an explicit falsification close with decision no_held_out_benefit_at_fixture_scale_retain_dag_only, invoking the issue's own stop rule verbatim: 'If replay-grounded history yields no held-out benefit, retain the event DAG for runtime/evaluation only and do not add preference training complexity.' Its non-goals state: 'No preference training complexity added — no SFT/preference training run, no checkpoint'.
This PR does exactly what the disposition forecloses:
- It runs a real
slm preference trainrun (20 steps) against the replay-preference train split and writes a trained checkpoint. - It does so against the same bounded synthetic fixture corpus (8 sessions, 36 train / 4 held-out pairs via
synthesize_bounded_session_corpus) that already produced theno_benefit_fixture_scaleceiling effect — its own measured verdict is againno_benefit_fixture_scale(1.0 baseline vs 1.0 trained on the 4-pair held-out split), confirming rather than rebutting the falsification. - It adds preference-training measurement machinery (
pairwise_preference_margin,held_out_pairwise_accuracy,evaluate_replay_preference_held_out_benefitintrain.pyplus two CLIs) whose sole purpose is to justify preference training — training complexity the disposition says not to add.
The disposition's own successor conditions (goal-drift guard I14) define what would re-open preference training: (1) a real, argument-bound corpus build — the VAR3-04/05 pattern, pointing the extraction/conversion pipeline at build_symbolic_operator_corpus real admitted documents — measured against current_state_only/derived-only baselines, and (2) a powered held-out split that the state-only feature cannot ceiling. Neither is met: this slice's corpus is the synthetic fixture, and its held-out split is the same 4 pairs.
The honest fix is not to land a seventh synthetic slice but, if the goal is still pursued, to satisfy successor condition (1) first: build the real argument-bound corpus and beat derived-only baselines on a powered split, then file the preference-training successor per I14. A PR that retrains on the same fixture that falsified the approach adds complexity without evidence and sets a precedent of working around falsification closes by relabeling them 'in progress'.
The code itself looks careful (fail-closed empty-split guard, honest version_stamps, fixture-scale labeling), but sound engineering of a disposition-contradicting direction is still the wrong direction. Do not merge in this form.
Tyler-R-Kendrick
left a comment
There was a problem hiding this comment.
You're right, closing this rather than trying to salvage it.
Verified independently: f5259ea (PR #1157) is a real, merged falsification-close disposition for this exact issue, and its non-goals explicitly say "no SFT/preference training complexity added." This PR's own measured result (no_benefit_fixture_scale, 1.0 baseline vs 1.0 trained on the same 8-session/40-row synthetic fixture) doesn't rebut that disposition — it's the same ceiling effect on the same fixture, just re-run with an actual training step added on top.
What happened: this PR's work was scoped from an earlier read of the repo state, before #1157 landed and merged — a genuine timing collision, not a disagreement with the disposition's reasoning. It should have re-checked for a closing disposition before adding preference-training machinery, and didn't.
Not attempting to rescue this into something that satisfies successor condition I14 (real argument-bound corpus via build_symbolic_operator_corpus, measured against derived-only baselines on a powered split) — that's a substantially different, larger PR, not a patch on this one. Closing as-is; if that work happens, it should be filed as its own successor per the disposition, starting from the corpus-build step, not from this branch.
Generated by Claude Code
Summary
Seventh slice of DSH5-10 (SLM-418). The sixth slice (v7) built and tested
PreferencePairconversion for the seven named replay-preference relation patterns but never wrote a pair to a corpus file or fed it into the real training harness. This slice closes exactly that gap for the bounded synthetic corpus (synthesize_bounded_session_corpus):PreferencePairsplits to real corpus files under the existingoutputs/data/preference/root (no shadow corpus tree).slm preference trainharness against a from-scratchwf_smoke_v2TwoTowerModelcheckpoint.pairwise_preference_margin/held_out_pairwise_accuracy/evaluate_replay_preference_held_out_benefittotrain.py, reusingdpo_loss's own log-prob machinery rather than a parallel scoring path.no_benefit_fixture_scale, not a benefit claim.claim_class: wiringthroughout.The DSH3-selected
TypedOperatorPolicyScorer, the four-baseline comparison, and CAP0/CAP1/CAP2 retention remain explicitly out of scope (unchanged from every prior slice's own scope notes).What changed
src/slm_training/harnesses/preference/replay_preference_corpus.py(new) — corpus conversion/writer.scripts/build_replay_preference_corpus.py(new) — CLI to write train/held-out pairs.scripts/measure_replay_preference_held_out_benefit.py(new) — CLI wrapping the held-out measurement.src/slm_training/harnesses/preference/train.py— new margin/accuracy/benefit-evaluation functions.src/slm_training/harnesses/preference/replay_preference_context_view_variants.py— additivetracefield onReplayPreferenceSessionV1.src/slm_training/resources/versions.json—harness.preference.replay_preference_context_view_variantsv2→v3; newharness.preference.replay_preference_corpusv1.tests/test_harnesses/preference/test_replay_preference_corpus.py(new, 8 tests),test_replay_preference_held_out_benefit.py(new, 7 tests), one added test intest_operator_history_pairs.py.docs/design/dsh5-10-replay-preference-rows.md— new "Seventh slice" section perdocumenting-experiment-results.Test plan
Independently re-verified in this session (not just the authoring agent's own report), with
NODE_OPTIONS=cleared per this repo's documented Node 22 constraint:pytest -q tests/test_harnesses/preference/test_replay_preference_corpus.py tests/test_harnesses/preference/test_replay_preference_held_out_benefit.py tests/test_harnesses/preference/test_operator_history_pairs.py→ 31 passedruff checkon every touched/created file → cleanpython -m scripts.verify_version_stamps --check --base origin/main→ ok (2 components touched)python -m scripts.repo_policy→ ok (tracked + untracked)python -m scripts.verify_decode_invariants→ exit 0No ship or benefit claim is made; this is
wiringevidence, consistent with every prior slice indocs/design/dsh5-10-replay-preference-rows.md.Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Generated by Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests